#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <sys/select.h>

#define ServerIP "127.0.0.1"
#define host_port 8000
MAXPROCESSNUM = 0;

void doit()
{
	int    fd=-1;
	int    val;
	struct sockaddr_in sin;

	if ((fd=socket(AF_INET, SOCK_STREAM, 0))<0)
		return;

	sin.sin_family=PF_INET;
	sin.sin_addr.s_addr=inet_addr(ServerIP);
	sin.sin_port=htons(host_port);
	memset(sin.sin_zero, 0, sizeof(sin.sin_zero));

	if (connect(fd, (struct sockaddr *)&sin, sizeof(sin))<0)
	{
		close(fd);
		return;
	}

	char buf[1024];
	pid_t pid = getpid();
//	snprintf((void*)buf, 1024, "process ID %u", pid);

	if(fd < 0)
	{
		printf("pid:%u, fd:%d, connect server falure\n", pid, fd);
		exit(-1);
	}
	
	while(1)
	{
		sleep(rand()%6);
		
		if(fd < 0)
			printf("%u, %d, socket down\n", pid, fd);
	
		snprintf((void*)buf, 1024, "process ID %u", pid);
		int len = send(fd, buf, strlen(buf)+1, 0); 


		if(len > 0)
		{
			printf("SEND: ok! pid:%u, fd:%d, (%s)\n", pid, fd, buf);
			fd_set  fdRead;
	    struct  timeval tmout;
    	tmout.tv_sec=10;
    	tmout.tv_usec=0;
    	FD_ZERO(&fdRead);
    	FD_SET(fd,&fdRead);

	    int ret = select(fd+1, &fdRead, 0, 0, &tmout);
	    if (ret <= 0)
 	   	{
 	      if (ret == 0)
        {
            /* select for recv timeout!   */
            printf("RECV: timeover pid:%u, fd:%d, recv < 0  and close\n", pid, fd);
            close(fd);
            exit(-1);
        }
        else
        {
            /* select for recv fail!   */
            printf("select fail\n");
            exit(-1);
        }
    	}
XX:
			memset(buf, 0x00, sizeof(buf));
			len = recv(fd, buf, sizeof(buf)-1, 0); 
			if(len > 0)
					printf("RECV: ok! pid:%u, fd:%d, (%s)\n", pid, fd, buf);
			else if(len == 0)
			{
//				close(fd);
				printf("RECV: continue pid:%u, fd:%d, recv = 0 and continue recv\n", pid, fd);
//				exit(1);
				goto XX;
			}
			else
			{
				close(fd);
				printf("RECV: failure pid:%u, fd:%d, recv < 0  and close\n", pid, fd);
				exit(-1);
			}
		}
		else
		{
			if( (errno == EINTR) || (errno == EAGAIN) )
			{
				printf("SEND: failure pid:%u, fd:%d, (%s), buffer overflure and again\n", pid, fd, buf);
				continue;
			}
			else
			{
				close(fd);
				printf("SEND: failure pid:%u, fd:%d, (%s), send < 0 and close\n", pid, fd, buf);
				exit(-1);
			}
		}
	}

	close(fd);
}

void InitProcess()
{
	int num_childs = MAXPROCESSNUM;
	if (num_childs > 0) {
		int child = 0;
		while (!child) {
			if (num_childs > 0) {
				switch (fork()) {
				case -1:
					exit(-1);
				case 0:
					child = 1;
					break;
				default:
					num_childs--;
					break;
				}
			} else {
				int status;
				if (-1 != wait(&status)) {
					num_childs++;
				} else {
					switch (errno) {
					case EINTR:
						kill(0, SIGHUP);
						break;
					default:
						break;
					}
				}
			}
		}

		/**
		 * for the parent this is the exit-point 
		 */
		if (!child) {
			kill(0, SIGINT);
			exit(0);
		}
	}
}


int main(int argc, char* argv[])
{
	if(argc != 2)
	{
		printf("param error\n");
		exit(1);
	}
	
	MAXPROCESSNUM = atoi(argv[1], 10);
	printf("maxprocess is: %d\n", MAXPROCESSNUM);
	
	InitProcess();
	doit();
}
